package user_news

import (
	"HeadLineNews/controller/app/vote"
	"HeadLineNews/pkg/db/store"
	"HeadLineNews/pkg/zaplog"
	models "HeadLineNews/proto_models/app/user_news_model"
	"HeadLineNews/proto_models/common"
	"HeadLineNews/resp"
	"HeadLineNews/utils/gin_ctx"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-redis/redis/v8"
	"github.com/jmoiron/sqlx"
	"strings"
	"time"
)

var (
	errNewsNotExists = errors.New("新闻不存在")
)

type Repo interface {
	UserRetrieveUser(c *gin.Context) (data *models.ResponseUserRetrieveNews, err error)
	UserListNews(c *gin.Context, p *common.PageSize) (data *models.ResponseUserListNews, err error)
}

type repo struct {
	db *sqlx.DB
}

func NewRepo() Repo {
	return &repo{db: store.DB()}
}

// UserRetrieveUser 用户检索单条新闻
func (r *repo) UserRetrieveUser(c *gin.Context) (data *models.ResponseUserRetrieveNews, err error) {
	newsId := c.Param("newsId")
	data = new(models.ResponseUserRetrieveNews)
	sqlStr := `SELECT n.news_id,n.news_title, n.news_content,n.news_score, n.create_time,
              c.category_name AS news_category, 
       		  GROUP_CONCAT(CONCAT_WS(';', au.author_id, au.author_name)) AS authors_tmp	
			  FROM app__news n,app__news_category c,
			       app__news_authors nas, app__author au
			  WHERE n.news_category=c.category_id
			  AND n.news_id=nas.news_id
			  AND nas.author_id=au.author_id
			  AND n.news_id=?`
	if err = r.db.Get(data, sqlStr, newsId); err != nil {
		if strings.Contains(err.Error(), "converting NULL to string is unsupported") {
			err = errNewsNotExists
			zaplog.L().Warn("no news was selected by id", zaplog.Fields(c, newsId, nil)...)
			resp.UnprovedParam(c, err.Error())
			return
		}
		zaplog.L().Error("query news by id failed", zaplog.Fields(c, newsId, err)...)
		resp.ServerBusy(c)
		return
	}
	// 判断得分
	if data.NewsScore == 0 {
		tz, _ := time.LoadLocation("Asia/Shanghai")
		t, _ := time.ParseInLocation("2006-01-02 15:04:05", data.CreateTime, tz)
		// 分数还未同步到 mysql

		if time.Now().Unix()-t.Unix() < vote.GetVoteExpireTime() {
			// 查询得分
			var score, voteRecord float64
			if score, err = vote.NewCache().GetNewsScoreByNewsId(data.NewsId); err != nil {
				zaplog.L().Error("query news score by newsId failed", zaplog.Fields(c, data.NewsId, err)...)
				resp.ServerBusy(c)
				return
			}
			data.NewsScore = int64(score)
			// 查询当前用户是否点赞了
			if voteRecord, err = vote.NewCache().GetNewsUserVoteRecord(data.NewsId, c.GetString(gin_ctx.UserId)); err != nil {
				if err == redis.Nil {
					err = nil
					voteRecord = 0
				}
				zaplog.L().Error("query user vote record by newsId failed",
					zaplog.Fields(c, fmt.Sprintf("newsId: %s, userId: %s", data.NewsId, c.GetString(gin_ctx.UserId)), err)...)
				resp.ServerBusy(c)
				return
			}
			data.IsLike = int64(voteRecord)
		}

	}
	//拆分作者
	authorsSl := strings.Split(data.AuthorTmp, ",")
	for _, author := range authorsSl {
		authorSL := strings.Split(author, ";")
		data.Authors = append(data.Authors, &models.ANewAuthor{
			AuthorId:   authorSL[0],
			AuthorName: authorSL[1],
		})
	}
	data.AuthorTmp = ""
	return
}

// UserListNews 用户请求新闻目录
func (r *repo) UserListNews(c *gin.Context, p *common.PageSize) (data *models.ResponseUserListNews, err error) {
	// 检索新闻以及对应的评论数量
	data = new(models.ResponseUserListNews)
	records := make([]*models.AItmNews, 0, p.Size)
	sqlStr := `SELECT n.news_id, n.news_title,n.news_score ,n.create_time, c.category_name, 
       			COUNT(nc.news_id) AS comment_count FROM 
		((app__news n INNER JOIN app__news_category c ON n.news_category=c.category_id) 
		LEFT JOIN app__news_comment nc ON n.news_id=nc.news_id) 
		GROUP BY n.news_id LIMIT ? OFFSET ?`
	if err = r.db.Select(&records, sqlStr, p.Size, (p.Page-1)*p.Size); err != nil {
		zaplog.L().Error("query news failed", zaplog.Fields(c, p, err)...)
		resp.ServerBusy(c)
		return
	}
	// 查询新闻得分
	var ids []string
	var indexes []int
	for i, news := range records {
		// 分数为 0，且新闻创建时间还在允许点赞的时间内，就筛选出 id
		if news.Score == 0 {
			tz, _ := time.LoadLocation("Asia/Shanghai")
			t, _ := time.ParseInLocation("2006-01-02 15:04:05", news.CreateTime, tz)
			if time.Now().Unix()-t.Unix() < vote.GetVoteExpireTime() {
				ids = append(ids, news.NewsId)
				indexes = append(indexes, i)
			}
		}
	}
	// redis 查询分数
	var scores, voteRecords []float64
	if scores, err = vote.NewCache().GetNewsScoreByNewsIds(ids...); err != nil {
		resp.ServerBusy(c)
		return
	}
	// 检查在有效点赞时间内有没有给这些新闻点过赞（已过点赞时间的只有分数，不显示是否点过赞，也不再不渲染点赞功能）
	if voteRecords, err = vote.NewCache().GetNewsUserVoteRecords(c.GetString(gin_ctx.UserId), ids...); err != nil {
		resp.ServerBusy(c)
		return
	}

	// 分数组装
	for i, index := range indexes {
		records[index].Score = int64(scores[i])
		records[index].IsLike = int64(voteRecords[i])
	}

	data.Records = records
	return
}